Don't let Your App Drain your Users' Battery
What drives battery Life?
- Hardware (Screen etc.)
- Operating System
- Apps & Services
- User Interaction
Efforts to improve battery
- Job Scheduler (Since API 21)
- Doze & App Standby(Since API 23)
- Doze on-the-go (Since API 24)
- Background Limits (Since API 26)
- Adaptive Battery, Background Restrictions etc. (Since API 28)
Among the above only Job Scheduler could be directly leveraged by app developers in the code.
Job Scheduler (Since API 21)
Job Scheduler is suitable when we want to do something in a specified circumstance, such as:
Batterry is not Low
With specified Netwoek Status
Is Charging
Storage is not Low
Device is Idle
Without Job Scheduler, we may need to keep a service running to monitor specified system broadcast and then do what we want, which is not optimized for battery comparing to Job Scheduler.
Here is a simple example of Job Scheduler:
1 | public class MyJobService extends JobService { |
Doze (Since API 23)
Unplugged and stationary for a period of time, a device would be in doze mode, which restricts all apps regardless whether they targets api 23. However, the OS periodically exits Doze for a brief time to let apps complete their deferred jobs. The bried time slot is called Maintenance window. Below is a figure showing the mode changing:
In doze mode, the following are restricted:
- Network access is suspended
- WakeLock is ignored
- Standard AlarmManager alarms (setExact() and setWindow()) are deferred to the next maintenance window
- No Wi-Fi scaning
- No Sync Adapters
- No JobScheduler jobs
Stuffs not restricted by Doze:
- FCM high priority msg
- Alarms set with setAndAllowWhileIdle() and setExactAndAllowWhileIdle()
Testing Doze:
1 | # if your device is connected with a cable, use the following to disable charging |
App Standby (Since API 23)
An app is idle if the followings are satisfies:
- No user touching for a certain period of time
- No processes in the foreground (either as an activity or foreground service)
- No notifications showing on the lock screen or in the notification center.
- Not charging
Testing App Standby:
1 | # if your device is connected with a cable, use the following to disable charging |
Doze on-the-go (Since API 24)
A lighter Doze mode which activates when the phone is moving in our pockets or hands. Doze on-the-go allows WakeLock, Wifi Scaning and GPS etc, that’s why it’s lighter than former Doze mode introduced in API 23.
Ignore Doze configuration:
Background Limits (Since API 26)
Background Limits affects apps that targets API 26 or higher and includes Background Service Limitations and Broadcast Limitations.
Background Service Limitations
For an app that targets API 26 or higher, it’s in background if:
- No visible Activity
- No foreground Service
- Not InputMethod Service, Wallpaper service etc.
After several minutes of being in background, background services are stopped by the OS. Replacing background services with Scheduler Jobs is fine in many cases.
Broadcast Limitations (Introduced in API 25 and strengthened in API 26)
For an app that targets API 26 or higher, it:
- can’t register receivers for implicit broadcasts in Manifest file
- can register receivers for explicit broadcasts in Manifest file
- can register receivers for any broadcasts runtimely
Broadcasts that require a signature permission are exempted from this restriction.
In some cases, registering system broadcasts could be replaced by Scheduler Jobs, such as if we want to do something when the device is charging.
Adaptive Battery (Since API 29)
A new feature based on Machine Learning.
- Limit battery for apps that are not used often.
- Apps should be able to run quickly when they are needed.
- Don’t bother users to manage manually.
Apps are arranged into 4 standby buckets: Active
, Working set
, Frequent
and Rare
. Limits are increased from Active
to Rare
:
An app is in Active
if it:
- has launched an activity
- is running a foreground service
- has a sync adapter associated with a content provider used by a foreground app
- has a notification clicked by the user
An app is in Working set
if it runs often but isn’t active.
An app is in Frequent
if it is used regularly, but not necessarily every day.
An app is in Rare
if it is not often used.
Find out what bucket the app is currently in programmatically:
1 | UsageStatsManager.getAppStandbyBucket() |
Test Standby Buckets:
1 | # assgin your app into a specified bucket |
Battery Saver
New battery saver in API 29:
- No red status bar and has animation
- Location service is off when screen is off
- Battery level threshold is adjustable
Apps are encouraged to switch to dark theme when battery saver is on.
Check whether battery saver is on programmatically:
1 | ((PowerManager)getSystemService(Context.POWER_SERVICE)).isPowerSaveMode() |
Test battery saver:
1 | # pretend to be in low battery status |
Background Restrictions (Since API 29)
Two criterias:
- Apps targeting pre-Oreo and using background services
- Excessive WakeLocks (> 1hr in background)
Background restrictions are decided by the users:
When Background Restrictions is enabled for an app, fllowings are restricted:
- Background jobs, alarms, services and network accessing
- Location related updates
- Foreground services
Except GUI operation, Background restrictions could alse be finished via adb:
1 | # enable background restrictions |